<?php

namespace App\Http\Controllers\Traits;

use Dingo\Api\Http\Response;
use Illuminate\Database\Eloquent\Builder;

trait IndexResource
{
    /**
     * Whether sorting is enabled or not
     *
     * @var bool
     */
    protected $sort = true;

    /**
     * Number of data bars per page
     *
     * @var int
     */
    protected $limit = 10;

    /**
     * Whether to return data in collection form
     *
     * @var bool
     */
    protected $all = false;

    /**
     * Default sort field
     *
     * @var string
     */
    protected $sort_column = 'id';

    /**
     * Default sort mode
     *
     * @var string
     */
    protected $sort_type = 'desc';

    /**
     * searchable
     *
     * @var array
     */
    protected $searchable = ['id'];

    /**
     * Filters
     *
     * @var int
     */
    protected static $filter_boolean = 0; // 布尔值筛选
    protected static $filter_like    = 1; // 模糊查询
    protected static $filter_equal   = 2; // 相等筛选
    protected static $filter_between = 3; // 区间筛选

    /**
     * Resource Controller for index method
     *
     * @return Response
     */
    public function index()
    {
        $this->model = $this->try('indexQuery', $this->model) ?? $this->model;

        $this->indexFilterQuery();

        $this->sortQuery();

        return $this->indexResponse();
    }

    /**
     * Return index resource
     */
    protected function indexResponse()
    {
        return $this->hasGetAll() ? $this->collectionResponse() : $this->paginatorResponse();
    }

    /**
     * Return collection response
     *
     * @return mixed
     */
    protected function collectionResponse()
    {
        return $this->success($this->model->get()->toArray());
    }

    /**
     * Return paginator response
     *
     * @return mixed
     */
    protected function paginatorResponse()
    {
        $pageRes = $this->model->paginate($this->getPerPage())->toArray();
        return $this->success(['count' => $pageRes['total'], 'data' => $pageRes['data']]);
    }

    /**
     * Return filterd query
     *
     * @return Resource
     */
    protected function indexFilterQuery()
    {
        $filters     = $this->try('filters', []);
        $this->model = $this->model->select($this->field);

        foreach ($filters as $key => $value) {
            if ( ! is_null($input = request()->get($key))) {
                switch ($value) {
                    case static::$filter_like:
                        $this->model = $this->model->where($key, 'like', '%'.$input.'%');
                        break;
                    case static::$filter_boolean:
                        $this->model = $this->model->where($key, (boolean) $input);
                        break;
                    case static::$filter_equal:
                        $this->model = $this->model->where($key, $input);
                        break;
                    case static::$filter_between:
                        $this->model = $this->model->whereBetween($key, $input);
                        break;
                }
            }
        }

        $search = request()->get('search');

        $this->model = $this->model->when(! is_null($search), function ($query) use ($search) {
            /** @var Builder $query */
            $query->where(function (Builder $query1) use ($search) {
                foreach ($this->searchable as $key => $searchable) {
                    $method = $key === 0 ? 'where' : 'orWhere';
                    $query1->$method($searchable, 'like', '%'.$search.'%');
                }
                return $query1;
            });
        });

        return $this->model;
    }

    /**
     * Sort query
     */
    public function sortQuery()
    {
        $this->model = $this->sort
            ? $this->model->orderBy($this->sort_column, $this->sort_type)
            : $this->model;
    }

    /**
     * Get per page
     *
     * @return mixed
     */
    protected function getPerPage()
    {
        return request()->get('limit', $this->limit);
    }

    /**
     * If is all
     *
     * @return bool
     */
    protected function hasGetAll(): bool
    {
        return $this->all || request()->get('all');
    }
}
